package ts;

import java.util.Enumeration;
import java.util.Hashtable;

public class TablaSimbolos {

	private Hashtable<String, Parametros> ts;
	private Hashtable<String, Parametros> tsl;

	public TablaSimbolos() {
		ts = new Hashtable<String, Parametros>();
	}

	public TablaSimbolos(TablaSimbolos tabla) {
		this.ts = new Hashtable<String, Parametros>();
		this.ts = (Hashtable<String, Parametros>) tabla.getTs().clone();
		if (tabla.tsl != null)
			this.tsl = (Hashtable<String, Parametros>) tabla.getTsl().clone();
	}

	public void anadeTS(String id, String clase, Tipo tipo, int dir) {
		if (tsl != null)
			tsl.put(id, new Parametros(id, clase, "local", tipo, dir));
		else
			ts.put(id, new Parametros(id, clase, "global", tipo, dir));
	}

	public void eliminaTSLocal() {
		this.tsl = null;
	}

	public void creaTSLocal() {
		this.tsl = new Hashtable<String, Parametros>();
	}

	

	public Tipo getTipo(String id) {
		if (tsl != null)
			return getTipoLocal(id);
		else
			return getTipoGlobal(id);
	}

	private Tipo getTipoLocal(String id) {
		if (tsl.containsKey(id))
			return tsl.get(id).getTipo();
		else
			return getTipoGlobal(id);
	}

	private Tipo getTipoGlobal(String id) {
		if (ts.containsKey(id))
			return ts.get(id).getTipo();
		return new TipoError();
	}

	public boolean existeId(String id) {
		if (tsl != null)
			return existeIdLocal(id);
		else
			return existeIdGlobal(id);
	}

	public boolean existeIdGlobal(String id) {
		return ts.containsKey(id);
	}

	private boolean existeIdLocal(String id) {
		if (tsl.containsKey(id))
			return true;
		else
			return existeIdGlobal(id);
	}

	public boolean existeIdSoloLocal(String id) {
		return (tsl.containsKey(id));
	}

	public String dameNivel(String id) {
		if (tsl != null)
			return dameNivelLocal(id);
		else
			return dameNivelGlobal(id);
	}

	private String dameNivelGlobal(String id) {
		if (ts.containsKey(id))
			return ts.get(id).getNivel();
		else
			return "";
	}

	private String dameNivelLocal(String id) {
		if (tsl.containsKey(id))
			return tsl.get(id).getNivel();
		else
			return dameNivelGlobal(id);
	}

	public String dameClase(String id) {
		if (tsl != null)
			return dameClaseLocal(id);
		else
			return dameClaseGlobal(id);
	}

	private String dameClaseGlobal(String id) {
		if (ts.containsKey(id))
			return ts.get(id).getClase();
		else
			return "";
	}

	private String dameClaseLocal(String id) {
		if (tsl.containsKey(id))
			return tsl.get(id).getClase();
		else
			return dameClaseGlobal(id);
	}

	public boolean esConst(String id) {
		if (tsl != null)
			return esConstLocal(id);
		else
			return esConstGlobal(id);
	}
	
	public int getDir(String id) {
		if (tsl != null)
			return getDirLocal(id);
		else
			return getDirGlobal(id);
	}

	private int getDirLocal(String id) {
		if (tsl.containsKey(id))
			return tsl.get(id).getDir();
		else
			return getDirGlobal(id);
	}

	private int getDirGlobal(String id) {
		if (ts.containsKey(id))
			return ts.get(id).getDir();
		return 0;
	}

	private boolean esConstGlobal(String id) {
		if (ts.containsKey(id))
			return ts.get(id).getClase().equals("const");
		return false;
	}

	private boolean esConstLocal(String id) {
		if (tsl.containsKey(id))
			return tsl.get(id).getClase().equals("const");
		else
			return esConstGlobal(id);
	}

	public boolean esNatural(String id) {
		if (tsl != null)
			return esNaturalLocal(id);
		else
			return esNaturalGlobal(id);
	}

	private boolean esNaturalGlobal(String id) {
		if (ts.containsKey(id))
			return ts.get(id).getTipo().getTipo().equals("natural");
		return false;
	}

	private boolean esNaturalLocal(String id) {
		if (tsl.containsKey(id))
			return tsl.get(id).getTipo().getTipo().equals("natural");
		else
			return esNaturalGlobal(id);
	}

	public char getValorCharacter(String id) {
		if (ts.containsKey(id))
			if (ts.get(id).tipo.getTipo().equals("character"))
				return ((TipoChar) ts.get(id).tipo).getValor();
		return 0;
	}

	private char getValorCharacterLocal(String id) {
		if (ts.containsKey(id))
			if (ts.get(id).tipo.getTipo().equals("character"))
				return ((TipoChar) ts.get(id).tipo).getValor();
		return 0;
	}

	private char getValorCharacterGlobal(String id) {
		if (ts.containsKey(id))
			if (ts.get(id).tipo.getTipo().equals("character"))
				return ((TipoChar) ts.get(id).tipo).getValor();
		return 0;
	}

	public int getValorInteger(String id) {
		if (tsl != null)
			return getValorIntegerLocal(id);
		else
			return getValorIntegerGlobal(id);
	}

	private int getValorIntegerGlobal(String id) {
		if (ts.containsKey(id))
			if (ts.get(id).tipo.getTipo().equals("integer"))
				return ((TipoInt) ts.get(id).tipo).getValor();
		return 0;
	}

	private int getValorIntegerLocal(String id) {
		if (tsl.containsKey(id))
			if (tsl.get(id).tipo.getTipo().equals("integer"))
				return ((TipoInt) tsl.get(id).tipo).getValor();
		return getValorIntegerGlobal(id);
	}

	public int getValorNatural(String id) {
		if (tsl != null)
			return getValorNaturalLocal(id);
		else
			return getValorNaturalGlobal(id);
	}

	private int getValorNaturalGlobal(String id) {
		if (ts.containsKey(id))
			if (ts.get(id).tipo.getTipo().equals("natural"))
				return ((TipoNat) ts.get(id).tipo).getValor();
		return 0;
	}

	private int getValorNaturalLocal(String id) {
		if (tsl.containsKey(id))
			if (tsl.get(id).tipo.getTipo().equals("natural"))
				return ((TipoNat) tsl.get(id).tipo).getValor();
		return getValorNaturalGlobal(id);
	}

	public float getValorFloat(String id) {
		if (tsl != null)
			return getValorFloatLocal(id);
		else
			return getValorFloatGlobal(id);
	}

	private float getValorFloatGlobal(String id) {
		if (ts.containsKey(id))
			if (ts.get(id).tipo.getTipo().equals("float"))
				return ((TipoFloat) ts.get(id).tipo).getValor();
		return 0;
	}

	private float getValorFloatLocal(String id) {
		if (tsl.containsKey(id))
			if (tsl.get(id).tipo.getTipo().equals("float"))
				return ((TipoFloat) tsl.get(id).tipo).getValor();
		return getValorFloatGlobal(id);
	}

	public boolean getValorBoolean(String id) {
		if (tsl != null)
			return getValorBooleanLocal(id);
		else
			return getValorBooleanGlobal(id);
	}

	private boolean getValorBooleanGlobal(String id) {
		if (ts.containsKey(id))
			if (ts.get(id).tipo.getTipo().equals("boolean"))
				return ((TipoBool) ts.get(id).tipo).getValor();
		return false;
	}

	private boolean getValorBooleanLocal(String id) {
		if (tsl.containsKey(id))
			if (tsl.get(id).tipo.getTipo().equals("boolean"))
				return ((TipoBool) tsl.get(id).tipo).getValor();
		return getValorBooleanGlobal(id);
	}

	public void muestraDatosTipo() {

		Enumeration e = ts.elements();

		while (e.hasMoreElements()) {
			Parametros c = (Parametros) e.nextElement();
			String id = c.getId();
			String clase = c.getClase();
			Tipo tipo = c.getTipo();
			int tam = c.getTipo().getTam();
			int dir = c.getDir();

			String mostrar = "clase: " + clase + ", id: " + id;

			if (tipo.getTipo().equals("natural"))
				mostrar += ", valor: " + ((TipoNat) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("integer"))
				mostrar += ", valor: " + ((TipoInt) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("float"))
				mostrar += ", valor: " + ((TipoFloat) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("character"))
				mostrar += ", valor: " + ((TipoChar) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("boolean"))
				mostrar += ", valor: " + ((TipoBool) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("array")) {
				mostrar += ", valor: <t: " + tipo.getTipo() + ", nelms: "
						+ ((TipoArray) tipo).getNumElem() + ", tbase: ";
				Tipo tb = ((TipoArray) tipo).getTipoBase();
				if (tb.getTipo().equals("ref"))
					mostrar += "< t: ref " + ", id: "
							+ ((TipoIdent) tb).getId() + " >";
				else if (tb.getTipo().equals("array"))
					mostrar += "< t: array , nelems: "
							+ ((TipoArray) tipo).getNumElem() + ", tbase: "
							+ ((TipoArray) tb).getTipoBase().getTipo() + " >";
				else if (tb.getTipo().equals("tupla"))
					mostrar += " <t: tupla, " + ", campos:"
							+ ((TipoTupla) tb).muestraCampos();
				else
					mostrar += " <t: " + tb.getTipo();
			} else if (tipo.getTipo().equals("tupla"))
				mostrar += " tipo: <t: " + tipo.getTipo() + ", campos:"
						+ ((TipoTupla) tipo).muestraCampos();
			else if (tipo.getTipo().equals("ref")) {
				mostrar += ", tipo: <t: " + tipo.getTipo() + ", id: "
						+ ((TipoIdent) tipo).getId();
			} else if (tipo.getTipo().equals("proc")) {
				mostrar += ", tipo: <t: " + tipo.getTipo() + ", campos: "
						+ ((TipoProc) tipo).muestraCampos();
			}

			mostrar += ", tam: " + tam + ">" + ", dir: " + dir;

			System.out.println(mostrar);

		}
	}

	public String muestraDatosTipo1() {

		Enumeration e = ts.elements();
		String mostrar="";

		while (e.hasMoreElements()) {
			Parametros c = (Parametros) e.nextElement();
		
			String id = c.getId();
			String clase = c.getClase();
			Tipo tipo = c.getTipo();
			int tam = c.getTipo().getTam();
			int dir = c.getDir();

			 mostrar+= "clase: " + clase + ", id: " + id;

			if (tipo.getTipo().equals("natural"))
				mostrar += ", valor: " + ((TipoNat) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("integer"))
				mostrar += ", valor: " + ((TipoInt) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("float"))
				mostrar += ", valor: " + ((TipoFloat) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("character"))
				mostrar += ", valor: " + ((TipoChar) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("boolean"))
				mostrar += ", valor: " + ((TipoBool) tipo).getValor()
						+ ", tipo: <t: " + tipo.getTipo();
			else if (tipo.getTipo().equals("array")) {
				mostrar += ", valor: <t: " + tipo.getTipo() + ", nelms: "
						+ ((TipoArray) tipo).getNumElem() + ", tbase: ";
				Tipo tb = ((TipoArray) tipo).getTipoBase();
				if (tb.getTipo().equals("ref"))
					mostrar += "< t: ref " + ", id: "
							+ ((TipoIdent) tb).getId() + " >";
				else if (tb.getTipo().equals("array"))
					mostrar += "< t: array , nelems: "
							+ ((TipoArray) tipo).getNumElem() + ", tbase: "
							+ ((TipoArray) tb).getTipoBase().getTipo() + " >";
				else if (tb.getTipo().equals("tupla"))
					mostrar += " <t: tupla, " + ", campos:"
							+ ((TipoTupla) tb).muestraCampos();
				else
					mostrar += " <t: " + tb.getTipo();
			} else if (tipo.getTipo().equals("tupla"))
				mostrar += " tipo: <t: " + tipo.getTipo() + ", campos:"
						+ ((TipoTupla) tipo).muestraCampos();
			else if (tipo.getTipo().equals("ref")) {
				mostrar += ", tipo: <t: " + tipo.getTipo() + ", id: "
						+ ((TipoIdent) tipo).getId();
			} else if (tipo.getTipo().equals("proc")) {
				mostrar += ", tipo: <t: " + tipo.getTipo() + ", campos: "
						+ ((TipoProc) tipo).muestraCampos();
			}

			mostrar += ", tam: " + tam + ">" + ", dir: " + dir;
			mostrar+="\n";
			

		}
		return mostrar;
	}
	
	
	public Hashtable<String, Parametros> getTs() {
		return ts;
	}

	public void setTs(Hashtable<String, Parametros> ts) {
		this.ts = ts;
	}

	public Hashtable<String, Parametros> getTsl() {
		return tsl;
	}

	public void setTsl(Hashtable<String, Parametros> tsl) {
		this.tsl = tsl;
	}

}
